#include "internal.h"

static void enqueue_top_rt_rq(struct rt_rq *rt_rq)
{
    struct rq *rq = rq_of_rt_rq(rt_rq);

    BUG_ON(&rq->rt != rt_rq);

    if (rt_rq->rt_queued)
        return;

    if (rt_rq_throttled(rt_rq))
        return;

    if (rt_rq->rt_nr_running)
    {
        add_nr_running(rq, rt_rq->rt_nr_running);
        rt_rq->rt_queued = 1;
    }
}

static void __enqueue_rt_entity(struct sched_rt_entity *rt_se, unsigned int flags)
{
    struct rt_rq *rt_rq = rt_rq_of_se(rt_se);
    struct rt_prio_array *array = &rt_rq->active;
    struct rt_rq *group_rq = group_rt_rq(rt_se);
    struct list_head *queue = array->queue + rt_se_prio(rt_se);

    /*
     * Don't enqueue the group if its throttled, or when empty.
     * The latter is a consequence of the former when a child group
     * get throttled and the current group doesn't have any other
     * active members.
     */
    if (group_rq && (rt_rq_throttled(group_rq) || !group_rq->rt_nr_running))
    {
        if (rt_se->on_list)
            __delist_rt_entity(rt_se, array);
        return;
    }

    if (move_entity(flags))
    {
        WARN_ON_ONCE(rt_se->on_list);
        if (flags & ENQUEUE_HEAD)
            list_add(&rt_se->run_list, queue);
        else
            list_add_tail(&rt_se->run_list, queue);

        __set_bit(rt_se_prio(rt_se), array->bitmap);
        rt_se->on_list = 1;
    }
    rt_se->on_rq = 1;

    inc_rt_tasks(rt_se, rt_rq);
}

static void enqueue_rt_entity(struct sched_rt_entity *rt_se, unsigned int flags)
{
    struct rq *rq = rq_of_rt_se(rt_se);

    update_stats_enqueue_rt(rt_rq_of_se(rt_se), rt_se, flags);

    dequeue_rt_stack(rt_se, flags);
    for_each_sched_rt_entity(rt_se)
        __enqueue_rt_entity(rt_se, flags);

    enqueue_top_rt_rq(&rq->rt);
}

/*
 * Adding/removing a task to/from a priority array:
 */
static void enqueue_task_rt(struct rq *rq, struct task_struct *p, int flags)
{
    struct sched_rt_entity *rt_se = &p->rt;

    if (flags & ENQUEUE_WAKEUP)
        rt_se->timeout = 0;

    check_schedstat_required();
    update_stats_wait_start_rt(rt_rq_of_se(rt_se), rt_se);

    enqueue_rt_entity(rt_se, flags);

    if (task_is_blocked(p))
        return;

    if (!task_current(rq, p) && p->nr_cpus_allowed > 1)
        enqueue_pushable_task(rq, p);
}
